#include <stdio.h>
#include "unidade_controle.h"
#include "memoria.h"
#include "multiplexador.h"
#include "registrador.h"
#include "parser.h"
#include "executa.h"

void next_micro (Unidade_Controle & UC, Memoria &memoria, ULA &ula, Multiplexador &mux, Multiplexador &muxA, Multiplexador &muxB,
        Registrador &RA, Registrador &RB, Registrador &R0, Registrador &R1, Registrador &R2, Registrador &R3, Registrador &R4,
        Registrador &PC, Registrador &Rdados, Registrador &Rend, Registrador &IR)
{
        bool sinal_a = UC.registrador_controle.controle['a'-'a'];
        bool sinal_b = UC.registrador_controle.controle['b'-'a'];
        bool sinal_c = UC.registrador_controle.controle['c'-'a'];
        bool sinal_d = UC.registrador_controle.controle['d'-'a'];
        bool sinal_e = UC.registrador_controle.controle['e'-'a'];
        bool sinal_f = UC.registrador_controle.controle['f'-'a'];
        bool sinal_g = UC.registrador_controle.controle['g'-'a'];
        bool sinal_h = UC.registrador_controle.controle['h'-'a'];
        bool sinal_i = UC.registrador_controle.controle['i'-'a'];
        bool sinal_j = UC.registrador_controle.controle['j'-'a'];
        bool sinal_k = UC.registrador_controle.controle['k'-'a'];
        bool sinal_l = UC.registrador_controle.controle['l'-'a'];
        bool sinal_m = UC.registrador_controle.controle['m'-'a'];
        bool sinal_n = UC.registrador_controle.controle['n'-'a'];
        bool sinal_o = UC.registrador_controle.controle['o'-'a'];
        bool sinal_p = UC.registrador_controle.controle['p'-'a'];
        bool sinal_q = UC.registrador_controle.controle['q'-'a'];
        bool sinal_r = UC.registrador_controle.controle['r'-'a'];
        bool sinal_s = UC.registrador_controle.controle['s'-'a'];
        bool sinal_t = UC.registrador_controle.controle['t'-'a'];
        bool sinal_u = UC.registrador_controle.controle['u'-'a'];
        bool sinal_v = UC.registrador_controle.controle['v'-'a'];
        bool sinal_w = UC.registrador_controle.controle['w'-'a'];

        /** Multiplexador A **/
        muxA.sinais_controle(0, sinal_m, sinal_n);
        int saida_muxA = muxA.multiplexa(Rdados.get(), R0.get(), R1.get(), RA.get(), 0);
        #ifdef DEBUG
                printf("saida Mux A: %d\n", saida_muxA);
        #endif

        /** Multiplexador B **/
        muxB.sinais_controle(sinal_o, sinal_p, sinal_q);
        int saida_muxB = muxB.multiplexa(PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
        #ifdef DEBUG
                printf("saida Mux B: %d\n", saida_muxB);
        #endif

        /** ULA **/
        ula.sinais_controle(sinal_s, sinal_t, sinal_u, sinal_v, sinal_w);
        int saida_ula = ula.operacao(saida_muxA, saida_muxB);
        #ifdef DEBUG
                printf("saida ULA: %d\n", saida_ula);
        #endif

        /** Registradores com conexao direta da ULA **/
        R0.sinal(sinal_a);
        R0 = saida_ula;

        R1.sinal(sinal_b);
        R1 = saida_ula;

        RA.sinal(sinal_c);
        RA = saida_ula;

        PC.sinal(sinal_d);
        PC = saida_ula;

        R2.sinal(sinal_e);
        R2 = saida_ula;

        R3.sinal(sinal_f);
        R3 = saida_ula;

        R4.sinal(sinal_g);
        R4 = saida_ula;

        RB.sinal(sinal_h);
        RB = saida_ula;

        IR.sinal(sinal_k);
        IR = saida_ula;

        Rend.sinal(sinal_i);
        Rend = saida_ula;

        /** Gerenciamento da memoria. leitura e escrita **/
        int saida_memoria = 0;
        if (sinal_r == 0) //Leitura
        {
                /** Memoria **/
                saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());

                /** MUX do Rdados **/
                mux.sinais_controle(0, 0, sinal_l);
                int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                /** Rdados **/
                Rdados.sinal(sinal_j);
                Rdados = saida_mux;
        }
        else if (sinal_r == 1) //Escrita
        {
                /** MUX do Rdados **/
                mux.sinais_controle(0, 0, sinal_l);
                int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                /** Rdados **/
                Rdados.sinal(sinal_j);
                Rdados = saida_mux;

                saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());
        }

        #ifdef DEBUG
                printf("Registradores:\n");
                printf("Rdados: %8d | R0: %8d | R1: %8d |              | RA: %8d\n", Rdados.get(), R0.get(), R1.get(), RA.get());
                printf("    PC: %8d | R2: %8d | R3: %8d | R4: %8d | RB: %8d\n", PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
                printf("  Rend: %8d | IR: %8d\n", Rend.get(), IR.get());
                printf("Zero: %d | Carry: %d | Negativo: %d\n", ula.get_flags().zero, ula.get_flags().carry, ula.get_flags().negativo);
        #endif

        //scanf("%*c");

        /** UC **/
        UC.ciclo_de_maquina(IR.get(), ula.get_flags());
}

void next_inst (Unidade_Controle & UC, Memoria &memoria, ULA &ula, Multiplexador &mux, Multiplexador &muxA, Multiplexador &muxB,
        Registrador &RA, Registrador &RB, Registrador &R0, Registrador &R1, Registrador &R2, Registrador &R3, Registrador &R4,
        Registrador &PC, Registrador &Rdados, Registrador &Rend, Registrador &IR)
{
        int inst = IR.get();

        while (IR.get() == inst)
        {
                bool sinal_a = UC.registrador_controle.controle['a'-'a'];
                bool sinal_b = UC.registrador_controle.controle['b'-'a'];
                bool sinal_c = UC.registrador_controle.controle['c'-'a'];
                bool sinal_d = UC.registrador_controle.controle['d'-'a'];
                bool sinal_e = UC.registrador_controle.controle['e'-'a'];
                bool sinal_f = UC.registrador_controle.controle['f'-'a'];
                bool sinal_g = UC.registrador_controle.controle['g'-'a'];
                bool sinal_h = UC.registrador_controle.controle['h'-'a'];
                bool sinal_i = UC.registrador_controle.controle['i'-'a'];
                bool sinal_j = UC.registrador_controle.controle['j'-'a'];
                bool sinal_k = UC.registrador_controle.controle['k'-'a'];
                bool sinal_l = UC.registrador_controle.controle['l'-'a'];
                bool sinal_m = UC.registrador_controle.controle['m'-'a'];
                bool sinal_n = UC.registrador_controle.controle['n'-'a'];
                bool sinal_o = UC.registrador_controle.controle['o'-'a'];
                bool sinal_p = UC.registrador_controle.controle['p'-'a'];
                bool sinal_q = UC.registrador_controle.controle['q'-'a'];
                bool sinal_r = UC.registrador_controle.controle['r'-'a'];
                bool sinal_s = UC.registrador_controle.controle['s'-'a'];
                bool sinal_t = UC.registrador_controle.controle['t'-'a'];
                bool sinal_u = UC.registrador_controle.controle['u'-'a'];
                bool sinal_v = UC.registrador_controle.controle['v'-'a'];
                bool sinal_w = UC.registrador_controle.controle['w'-'a'];

                /** Multiplexador A **/
                muxA.sinais_controle(0, sinal_m, sinal_n);
                int saida_muxA = muxA.multiplexa(Rdados.get(), R0.get(), R1.get(), RA.get(), 0);
                #ifdef DEBUG
                        printf("saida Mux A: %d\n", saida_muxA);
                #endif

                /** Multiplexador B **/
                muxB.sinais_controle(sinal_o, sinal_p, sinal_q);
                int saida_muxB = muxB.multiplexa(PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
                #ifdef DEBUG
                        printf("saida Mux B: %d\n", saida_muxB);
                #endif

                /** ULA **/
                ula.sinais_controle(sinal_s, sinal_t, sinal_u, sinal_v, sinal_w);
                int saida_ula = ula.operacao(saida_muxA, saida_muxB);
                #ifdef DEBUG
                        printf("saida ULA: %d\n", saida_ula);
                #endif

                /** Registradores com conexao direta da ULA **/
                R0.sinal(sinal_a);
                R0 = saida_ula;

                R1.sinal(sinal_b);
                R1 = saida_ula;

                RA.sinal(sinal_c);
                RA = saida_ula;

                PC.sinal(sinal_d);
                PC = saida_ula;

                R2.sinal(sinal_e);
                R2 = saida_ula;

                R3.sinal(sinal_f);
                R3 = saida_ula;

                R4.sinal(sinal_g);
                R4 = saida_ula;

                RB.sinal(sinal_h);
                RB = saida_ula;

                IR.sinal(sinal_k);
                IR = saida_ula;

                Rend.sinal(sinal_i);
                Rend = saida_ula;

                /** Gerenciamento da memoria. leitura e escrita **/
                int saida_memoria = 0;
                if (sinal_r == 0) //Leitura
                {
                        /** Memoria **/
                        saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());

                        /** MUX do Rdados **/
                        mux.sinais_controle(0, 0, sinal_l);
                        int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                        /** Rdados **/
                        Rdados.sinal(sinal_j);
                        Rdados = saida_mux;
                }
                else if (sinal_r == 1) //Escrita
                {
                        /** MUX do Rdados **/
                        mux.sinais_controle(0, 0, sinal_l);
                        int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                        /** Rdados **/
                        Rdados.sinal(sinal_j);
                        Rdados = saida_mux;

                        saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());
                }

                #ifdef DEBUG
                        printf("Registradores:\n");
                        printf("Rdados: %8d | R0: %8d | R1: %8d |              | RA: %8d\n", Rdados.get(), R0.get(), R1.get(), RA.get());
                        printf("    PC: %8d | R2: %8d | R3: %8d | R4: %8d | RB: %8d\n", PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
                        printf("  Rend: %8d | IR: %8d\n", Rend.get(), IR.get());
                        printf("Zero: %d | Carry: %d | Negativo: %d\n", ula.get_flags().zero, ula.get_flags().carry, ula.get_flags().negativo);
                #endif

                //scanf("%*c");

                /** UC **/
                UC.ciclo_de_maquina(IR.get(), ula.get_flags());
        }
}

void direto (Unidade_Controle &UC, Memoria &memoria, ULA &ula, Multiplexador &mux, Multiplexador &muxA, Multiplexador &muxB,
        Registrador &RA, Registrador &RB, Registrador &R0, Registrador &R1, Registrador &R2, Registrador &R3, Registrador &R4,
        Registrador &PC, Registrador &Rdados, Registrador &Rend, Registrador &IR)
{
        while (IR.get() != 718)
        {
                bool sinal_a = UC.registrador_controle.controle['a'-'a'];
                bool sinal_b = UC.registrador_controle.controle['b'-'a'];
                bool sinal_c = UC.registrador_controle.controle['c'-'a'];
                bool sinal_d = UC.registrador_controle.controle['d'-'a'];
                bool sinal_e = UC.registrador_controle.controle['e'-'a'];
                bool sinal_f = UC.registrador_controle.controle['f'-'a'];
                bool sinal_g = UC.registrador_controle.controle['g'-'a'];
                bool sinal_h = UC.registrador_controle.controle['h'-'a'];
                bool sinal_i = UC.registrador_controle.controle['i'-'a'];
                bool sinal_j = UC.registrador_controle.controle['j'-'a'];
                bool sinal_k = UC.registrador_controle.controle['k'-'a'];
                bool sinal_l = UC.registrador_controle.controle['l'-'a'];
                bool sinal_m = UC.registrador_controle.controle['m'-'a'];
                bool sinal_n = UC.registrador_controle.controle['n'-'a'];
                bool sinal_o = UC.registrador_controle.controle['o'-'a'];
                bool sinal_p = UC.registrador_controle.controle['p'-'a'];
                bool sinal_q = UC.registrador_controle.controle['q'-'a'];
                bool sinal_r = UC.registrador_controle.controle['r'-'a'];
                bool sinal_s = UC.registrador_controle.controle['s'-'a'];
                bool sinal_t = UC.registrador_controle.controle['t'-'a'];
                bool sinal_u = UC.registrador_controle.controle['u'-'a'];
                bool sinal_v = UC.registrador_controle.controle['v'-'a'];
                bool sinal_w = UC.registrador_controle.controle['w'-'a'];

                /** Multiplexador A **/
                muxA.sinais_controle(0, sinal_m, sinal_n);
                int saida_muxA = muxA.multiplexa(Rdados.get(), R0.get(), R1.get(), RA.get(), 0);
                #ifdef DEBUG
                        printf("saida Mux A: %d\n", saida_muxA);
                #endif

                /** Multiplexador B **/
                muxB.sinais_controle(sinal_o, sinal_p, sinal_q);
                int saida_muxB = muxB.multiplexa(PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
                #ifdef DEBUG
                        printf("saida Mux B: %d\n", saida_muxB);
                #endif

                /** ULA **/
                ula.sinais_controle(sinal_s, sinal_t, sinal_u, sinal_v, sinal_w);
                int saida_ula = ula.operacao(saida_muxA, saida_muxB);
                #ifdef DEBUG
                        printf("saida ULA: %d\n", saida_ula);
                #endif

                /** Registradores com conexao direta da ULA **/
                R0.sinal(sinal_a);
                R0 = saida_ula;

                R1.sinal(sinal_b);
                R1 = saida_ula;

                RA.sinal(sinal_c);
                RA = saida_ula;

                PC.sinal(sinal_d);
                PC = saida_ula;

                R2.sinal(sinal_e);
                R2 = saida_ula;

                R3.sinal(sinal_f);
                R3 = saida_ula;

                R4.sinal(sinal_g);
                R4 = saida_ula;

                RB.sinal(sinal_h);
                RB = saida_ula;

                IR.sinal(sinal_k);
                IR = saida_ula;

                Rend.sinal(sinal_i);
                Rend = saida_ula;

                /** Gerenciamento da memoria. leitura e escrita **/
                int saida_memoria = 0;
                if (sinal_r == 0) //Leitura
                {
                        /** Memoria **/
                        saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());

                        /** MUX do Rdados **/
                        mux.sinais_controle(0, 0, sinal_l);
                        int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                        /** Rdados **/
                        Rdados.sinal(sinal_j);
                        Rdados = saida_mux;
                }
                else if (sinal_r == 1) //Escrita
                {
                        /** MUX do Rdados **/
                        mux.sinais_controle(0, 0, sinal_l);
                        int saida_mux = mux.multiplexa(saida_memoria, saida_ula, 0, 0, 0);

                        /** Rdados **/
                        Rdados.sinal(sinal_j);
                        Rdados = saida_mux;

                        saida_memoria = memoria.acesso(sinal_r, Rend.get(), Rdados.get());
                }

                #ifdef DEBUG
                        printf("Registradores:\n");
                        printf("Rdados: %8d | R0: %8d | R1: %8d |              | RA: %8d\n", Rdados.get(), R0.get(), R1.get(), RA.get());
                        printf("    PC: %8d | R2: %8d | R3: %8d | R4: %8d | RB: %8d\n", PC.get(), R2.get(), R3.get(), R4.get(), RB.get());
                        printf("  Rend: %8d | IR: %8d\n", Rend.get(), IR.get());
                        printf("Zero: %d | Carry: %d | Negativo: %d\n", ula.get_flags().zero, ula.get_flags().carry, ula.get_flags().negativo);
                #endif

                /** UC **/
                UC.ciclo_de_maquina(IR.get(), ula.get_flags());
        }
}

